package com.syl.upimg.service;

import com.syl.upimg.bean.BaseBean;
import com.syl.upimg.utils.JsonUtils;
import com.syl.upimg.utils.RegexUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 基础上传接口
 *
 * @author syl
 * @create 2019-05-05 17:40
 **/
public interface BaseUpload {
    Logger LOG = LoggerFactory.getLogger(BaseUpload.class);

    RestTemplate createRestTemplate();

    /**
     * 获取最简单的请求头
     * @return
     */
    default HttpHeaders getDefaultHeader(){
        return getDefaultHeader(null, null);
    }

    /**
     * 获取文件的MIME 类型
     * @param file
     * @return
     */
    default String getMimeType(FileSystemResource file){
        String type = null;
        Path path = Paths.get(file.getFilename());
        try {
            type = Files.probeContentType(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return type;
    }

    default MediaType getMediaType(){
        return MediaType.MULTIPART_FORM_DATA;
    }

    default HttpHeaders getDefaultHeader(String origin, String referer){
        HttpHeaders defaultHeader = new HttpHeaders();
        defaultHeader.add("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36");
        if(StringUtils.isNotEmpty(origin))
            defaultHeader.add("Origin", origin);
        if(StringUtils.isNotEmpty(referer))
            defaultHeader.add("Referer", referer);
        String cookie = getCookie();
        if(StringUtils.isNotEmpty(cookie))
            defaultHeader.add("Cookie", cookie);
        defaultHeader.setContentType(getMediaType());
        return defaultHeader;
    }

    /**
     * 设置参数并返回参数对象
     * @param file 原始文件对象
     * @param fileName 文件名 不带后缀 如需带后缀的使用file.getFilename()活动
     * @param fileType 文件类型 不带.非 MIME 文件类型 如需MIME 请使用getContentType方法获取
     * @return
     */
    LinkedMultiValueMap<String, Object> getParam(FileSystemResource file, String fileName, String fileType);

    /**
     * 获取json 参数
     * @param filePath
     * @return
     */
    default String getJson(String filePath) {
        return null;
    }

    /**
     * 上传 指定返回string类型
     * @param filePath
     * @param delete
     * @return
     * @throws IOException
     */
    default String uploadByString(String filePath, boolean delete) throws IOException {
        return upload(filePath, String.class, delete);
    }

    /**
     * 上传 不删除文件
     * @param filePath
     * @param cz
     * @return
     */
    default <T> T upload(String filePath, Class<? extends BaseBean> cz) throws IOException {
        return (T) upload(filePath, cz, false);
    }

    /**
     * 上传
     * @param filePath
     * @param cz 空则返回String类型
     * @param delete 是否删除上传前文件
     * @param <T>
     * @return
     */
    default <T> T upload(String filePath, Class<T> cz, boolean delete) throws IOException {
        long startTime = System.currentTimeMillis();
        File file = new File(filePath);
        if(file.length() > getMaxSize() * 1024 * 1024)
            throw new IllegalArgumentException("图片大小超过最大限制");
        String[] limit = getLimit();
        String fileName = file.getName();
        if(limit != null) {
            List<String> list = new ArrayList<>(Arrays.asList(limit)); // as list的array缺少部分方法 这里转成完全体array
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            if (!list.contains(fileType) && !list.contains(fileType.substring(1)))
                throw new IllegalArgumentException("不支持的图片类型");
        }
        RestTemplate restTemplate = createRestTemplate();
        HttpHeaders defaultHeader = getDefaultHeader();
        String[] split = fileName.split("\\.");
        HttpEntity httpEntity;
        MultiValueMap<String, Object> requestBody = getParam(new FileSystemResource(file), split[0], split[1]);
        if (requestBody != null) httpEntity = new HttpEntity<>(requestBody, defaultHeader);
        else httpEntity = new HttpEntity<>(getJson(filePath), defaultHeader);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(getUrl(), httpEntity, String.class);
        HttpStatus statusCode = responseEntity.getStatusCode();
        LOG.debug("上传状态码 ====== {}", statusCode);
        String body = responseEntity.getBody();
        long endTime = System.currentTimeMillis();
        int time = new Long(endTime - startTime).intValue();
        LOG.debug("上传耗时 ====== {}", time);
        FileInputStream fileInputStream = null;
        String md5 = null;
        try {
            fileInputStream = new FileInputStream(file);
            md5 = DigestUtils.md5DigestAsHex(fileInputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) fileInputStream.close();
            if(delete){
                LOG.debug("准备删除图片=======");
                Files.delete(Paths.get(filePath));
            }
        }
        if (cz != null && cz != String.class){
            StringBuilder sb = new StringBuilder(RegexUtils.removeAll(body, "[\r\n]"));
            sb.insert(sb.length() - 1, ",\"timerMs\": " + time + ",\"md5\": \"" + md5 + "\"");
            return JsonUtils.fromJson(sb.toString(), cz);
        }
        return (T) body;
    }

    /**
     * 获取cookie
     * @return
     */
    default String getCookie(){
        return null;
    }

    /**
     * 图片类型限制列表
     * @return
     */
    String[] getLimit();

    /**
     * 图片最大大小限制 单位M
     * @return
     */
    default int getMaxSize(){
        return 5;
    }

    String getUrl();
}
